Microsoft CodeView and Utilities
================================
CHAPTER 8 ___ MANAGING WATCH STATEMENTS

Watch Statement commands are among the Microsoft CodeView debugger's most
powerful features.  They enable you to set, delete, and list watch statements.
Watch statements describe expressions or areas of memory to watch.  Some watch
statements specify conditional breakpoints, which depend upon the value of the
expression or memory area.
----
Note
----
Syntax for each CodeView command is always the same, regardless of the
expression evaluator; however, the method for specifying an argument may
vary with the language.  Therefore, each example in this chapter is
repeated with C, FORTRAN, BASIC, and Pascal arguments.  The sample screens
throughout the text that present these examples feature BASIC.  At the end
of this chapter are C, FORTRAN, AND Pascal sample screens, each of which
incorporates all the previous examples (except for Watch Delete and Watch
List).
====

The Watch Statement commands are summarized below:

Command			Action
--------------------------
Watch (W)		Sets an expression or range of memory to be watched

Watchpoint (WP)		Sets a conditional breakpoint that will be taken when
			the expression becomes nonzero (true)

Tracepoint (TP)		Sets a conditional breakpoint that will be taken when
			a given expression or range of memory changes

Watch Delete (Y)	Deletes one or more watch statements

Watch List (W)		Lists current watch statements

Watch statements, like breakpoints, remain in memory until you specifically
remove them or quit the CodeView debugger.  They are not canceled when you
restart the program being debugged.  Therefore, you can set a complicated
series of watch statements once, and then execute through the program several
times without resetting.

In window mode, Watch Statement commands can be entered either in the dialog
window or with menu selections.  Current watch statements are shown in a watch
window that appears between the menu bar and the source window.  In sequential
mode, the Watch, Tracepoint, and Watchpoint commands can be used, but since
there is no watch window, you cannot see the watch statements and their
values.  You must use the Watch List command to examine the current watch
statements.
----
Note
----
In order to set a watch statement containing a local variable, you must be
in the function where the variable is defined.  If the current line is not
in the function, the CodeView debugger displays the message UNKNOWN SYMBOL.
When you exit from a function containing a local variable referenced in a
watch statement, the value of the statement is displayed as UNKNOWN SYMBOL.
When you reenter the function, the local variable will again have a value.
With the C and FORTRAN expression evaluators, you can avoid this limitation
by using the period operator to specify both the function and the variable.
For example, enter main.x instead of just x.
====

8.1  Setting Watch-Expression and Watch-Memory Statements

The Watch command is used to set a watch statement that specifies an
expression (watch-expression statement) or a range of addresses in memory
(watch-expression statement) or a range of addresses in memory (watch-memory
statement).  The value or values specified by this watch statement are shown
in the watch window.  The watch window is updated to show new values each time
the value of the watch statement changes during program execution.  Since the
watch window does not exist in sequential mode, you must use the Watch List
command to examine the values of watch statements.

When setting a watch expression, you can specify the format in which the value
will be displayed.  Type the expression followed by a comma and a format
specifier.  If you do not give a format specifier, the CodeView debugger
displays the value in a default format.  See Section 6.1, "Display Expression
Command," for more information about type specifiers and the default format.
----
Note
----
If your program directly accesses absolute addresses used by IBM or IBM-
compatible computers, you may sometimes get unexpected results with the
Display Expression and Dump commands.  However, the Watch command will
usually show the correct values.  This problem can arise if the CodeView
debugger and your program begin to use the same memory location.

The problem often occurs when a program reads data directly from the screen
buffer of the display adapter.  If you have an array called  screen  that
is initialized to the starting address of the screen buffer, the command
DB screen L 16  will display data from the program's display (provided
screen swapping or screen flipping was specified at startup).  The Watch
command behaves differently from the Dump command because watch-statement
values are updated during program execution, and any values read from the
screen bugger will be taken from the output screen rather than from the
debugging screen.
====

<*> Mouse

To set a watch-expression statement using the mouse, point to Watch on the
menu bar, press a mouse button and drag the highlight down to Add Watch
selection, and then release the button.  A dialog box appears, asking for the
expression to be watched.  Type the expression and press the ENTER key or a
mouse button.

You cannot use the mouse version of the command to specify a range of memory
to be watched, as you can with the dialog version.

<*> Keyboard

To set a watch-expression statement with a keyboard command, press ALT+W to
open the Watch menu, and then type A (uppercase or lower) to select Add Watch.
You can also select the Add Watch command directly by pressing CONTROL+W.  A
dialog box appears, asking for the expression to be watched.  Type the
expression and press the ENTER key.

You cannot use the keyboard version of the command to specify a range of
memory to be watched, as you can with the dialog version.

<*> Dialog

To set a watch-expression statement or watch-memory statement with a dialog
command, enter a command line with the following syntax:

W? expression[,format]          Watch expression
W[type] range                   Watch memory

An expression used with the Watch command can be either a simple variable or a
complex expression using several variables and operators.  The expression
should be no longer than the width of the watch window.  The characters
permitted for format correspond to format arguments used in a C printf
function call.  See Section 6.1, "Display Expression Command," for more
information on format arguments.

When watching a memory location, type is a one-letter size specifier from the
following list:

Specifier	Size
--------------------
None		Default type
B		Byte
A		ASCII
I		Integer (signed decimal word)
U		Unsigned (unsigned decimal word)
W		Word
D		Double word
S		Short real
L		Long real
T		10-byte real

If no type size is specified, the default type used is the last type used by a
Dump, Enter, Watch, Memory, or Tracepoint Memory command.  If none of these
commands has been used during the session, the default type is byte.

The data will be displayed in a format similar to that used by the Dump
commands (see Section 6.1, "Display Expression Command," for more information
on format arguments).  The range can be any length, but only one line of data
will be displayed in the watch window.  If you do not specify an ending
address for the range, the default range is one object.

<*> Examples

The following three examples display watch statements in the watch window.

W? n

The example above displays the current value of the variable n.

W? higher * 100

The example above displays the value of the expression   higher * 100.

WL chance

The example above displays the double-precision floating-point  chance, first
showing exactly how it is stored in memory. (The command W? chance would
display the value of chance but not any actual bytes of memory.)

These commands, entered while debugging a BASIC program, produce the watch
window in Figure 8.1.  Corresponding C, FORTRAN, and Pascal examples are
included with other commands in language-specific sections at the end of the
chapter.

Figure 8.1  Watch Statements in the Watch Window  [SEE TEXT]

8.2  Setting Watchpoints

The Watchpoint command is used to set a conditional breakpoint called a
watchpoint.  A watchpoint breaks program execution when the expression
described by its watch statement becomes true.  You can think of watchpoints
as "break when" points, since the break occurs when the specified expression
becomes true (nonzero).

A watch statement created by the Watchpoint command describes the expression
that will be watched and compared to ).  The statement remains in memory until
you delete it or quit the CodeView debugger.  Any valid CodeView expression
can be used as the watchpoint expression as long as the expression is not
wider than the watch window.

In window mode, watchpoint statements and their values are displayed in high-
intensity text in the watch window.  In sequential mode, there is no watch
window, so the values of watchpoint statements can only be displayed with the
Watch List command (see Section 8.5, "Listing Watchpoints and Tracepoints,"
for more information).

Although watchpoints can be any valid CodeView expression, the command works
best with expressions that use the relational operators (such as < and > for C
and BASIC, or .LT. and .GT. for FORTRAN).  Relational expressions always
evaluate to false (zero) or true (nonzero).  Care must be taken with other
kinds of expressions when used as watchpoints because the watchpoints will
break execution whenever they do not equal precisely zero.  For example, your
program might use a loop variable  I, which ranges from 1 to 100.  If you
entered  I as a watchpoint, then it would always suspend program exection,
since  I is never equal to 0.  However, the relational expression  I>90 (or
I.GT.90) would not suspend program execution until  I exceeded 90.
<*> Mouse

To set a watchpoint statement with the mouse, point to Watch on the menu bar,
press a mouse button and draq the highlight down to the Watchpoint selection,
and then release the button.  A dialog box appears, asking for the expression
to be watched.  Type the expression and press the ENTER key or a mouse button.

<*> Keyboard

To execute the Watchpoint command with a keyboard command, press ALT+W to open
the Watch menu, and then press ALT+W to select Watchpoint.  A dialog box
appears, asking for the expression to be watched.  Type the expression and
press the ENTER key.

<*> Dialog

To set a watchpoint using a dialog command, enter a command line with the
following syntax:

WP? expression[,format]

The expression can be any valid CodeView expression (usually a relational
expression).  You can enter a format specifier, but there is little reason to 
do so, since the expression value is normally either 1 or 0.

<*> Examples

The following dialog commands display two watch statements (watchpoints) in
the watch window:

WP? higher > chance		;* BASIC/C/Pascal example
WP? higher .gt. chance		;* FORTRAN example

The examples above instruct the CodeView debugger to break execution when the
variable  higher  is greater than the variable  chance.  (Note that BASIC, C,
and Pascal happen to use the same syntax in this case, but FORTRAN uses its
own.)  After setting this watchpoint, you could use the Go command to execute
until the condition becomes true.

WP? n=7 or n=11			;* BASIC example
WP? n==7 || n==11		;* C example
WP? n.eq.7 .or. n.eq.11		;* FORTRAN example
WP? (n=7) or (n=11)		;* Pascal example

The examples above instruct the CodeView debugger to break execution when the
variable  n is equal to 7 or 11.
----
Note
----
BASIC and C will each display a numerical result in response to a Boolean
expression (0 being equivalent to false, nonzero to true).  However, the
corresponding FORTRAN condition will be displayed with either .TRUE. or
.FALSE. in the watch window.  Pascal will display TRUE or FALSE.
====

These commands, entered while debugging a BASIC program, produce the watch
window in Figure 8.2.  Corresponding C, FORTRAN, and Pascal examples are
included with other commands, at the end of the chapter.

	Figure 8.2 Watchpoints in the Watch Window  [SEE TEXT]
----
Note
----
Setting watchpoints significantly slows execution of the program being
debugged.  The CodeView debugger checks if the expression is true each time
a source line is executed in source mode, or each time an instruction is
executed in assembly mode.  Be careful when setting watchpoints near large
or nested loops.  A loop that executes almost instantly when run from MS-DOS
can take many minutes if executed from within the debugger with several
watchpoints set.

Tracepoints do not slow CodeView execution as much as watchpoints, so you
should use tracepoints when possible.  For example, although you can set a
watchpoint on a Boolean variable (WP? moving), a tracepoint on the same
variable (TP? moving) has essentially the same effect and does not slow
execution as much.

If you enter a seemingly endless loop, press CONTROL+BREAK or CONTROL+C to
exit.  You will soon learn the seze of loop you can safely execute when
watchpoints are set.
====

8.3  Setting Tracepoints

The Tracepoint command is used to set a conditional breakpoint called a
tracepoint.  A tracepoint breaks program execution when the value of a
specified expression or range of memory changes.

The watch statement created by the Tracepoint command describes the expression
or memory range to be watched and tested for change.  The statement remains in
memory until you delete it or quit the CodeView debugger.

In window mode, tracepoint statements and their values are shown in high-
intensity text in the watch window.  In sequential mode, there is no watch
window, so the values of tracepoint statements can only be displayed with the
Watch List command (see Section 8.5, "Listing Watchpoints and Tracepoints,"
for more information).

An expression used with the Tracepoint conmmand must evaluate to an "lvalue."
In other words, the expression must refer to an area of memory rather than a
constant.  Furthermore, the area of memory must be not more than 128 bytes in
size.  For example, i==10 (which is similar to I.EQ.10 in FORTRAN and I=10 in
BASIC) would be invalid because it is either 1 (true) or 0 (false) rather than
a value stored in memory.  The expression  sym1+sym2 is invalid because it is
the calculated sum of the value of two memory locations.  The expression
buffer  would be invalid if  buffer  is an array of 130 bytes, but valid if
the array is 120 bytes. (However, using array names this way is not valid with
BASIC modules because basic uses array descriptors.) Note that if  buffer  is
declared as an array of 64 bytes of the array.  The same command given with
the C expression  buffer[32], or BUFFER(33) in FORTRAN or BASIC, means that
only one byte (the 33rd) will be checked. (Note that C and FORTRAN index the
same element differently.)
----
Note
----
The following is relevant only to C programs.

Register variables are not considered lvalues.  Therefore, if i is declared
as  register int i, the command TP? i is invalid.  However, you can still
check for changes in the value of i.  Use the Examine Symbols command to
learn which register contains the value of i.  Then learn the value of i.
Finally, set up a watchpoint to test the value.  For example, use the
following sequence of commands:

>X? i
3A79:0264 int                div()
             SI      int             i
>?i
10
>WP? @SI!=10
>

====

When setting a tracepoint expression, you can specify the format in which the
value will be displayed.  Type the expression followed by a comma and a type
specifier.  If you do not give a type specifier, the CodeView debugger
displays the value in a default format.  See Section 6.1, "Display Expression
Command," for more information about type specifers and the default format.

<*> Mouse

To set a tracepoint-expression statement with the mouse, point to Watch on the
menu bar, press a mouse button and drag the highlight down to the Tracepoint
selection, and then release the button.  A dialog box appears asking for the
expression to be watched.  Type the expression, and press the ENTER key or a
mouse button.

You cannot specify a range of memory to be watched with the mouse version of
the command, as you can with the dialog version.

<*> Keyboard

To set a tracepoint-expression statement with a keyboard command, press ALT+W
to open the Watch menu, and then press ALT+T to select Tracepoint.  A dialog
box appears, asking for the expression to be watched.  Type the expression and
press the ENTER key.

You cannot use the keyboard version of the command to specify a range of
memory to be watched, as you can with the dialog version.

<*> Dialog

To set a tracepoint with a dialog command, enter a command line with one of
the following forms of syntax:

TP? expression,[format]		Tracepoint expression
TP[type] range			Tracepoint memory

An expression used with the Tracepoint command can be either a simple variable
or a complex expression using several variables and operators.  The expression
should not be longer than the width of the watch window.  You can specify
format using a C printf type specifier if you do not want the value to be
displayed in the default format (decimal for integers or floating point for
real numbers).  See Section 6.1, "Display Expression Command," for more
information on format arguments.

In the memory-tracepoint form, range must be a valid address range and type
must be a one-letter memory-size specifier.  If you specify only the start of
the range, the CodeView debugger displays one object as the default.

Although no more than one line of data will be displayed in the watch window,
the range to be checked for change can be any size up to 128 bytes.  The data
will be displayed in the format used by the Dump commands (see Section 6.1,
"Display Expression Command," for more information on format arguments).The 
valid memory-size specifiers are listed below:

Specifier	Size
--------------------
None		Default type
B		Byte
A		ASCII
I		Integer (signed decimal word)
U		Unsigned (unsigned decimal word)
W		Word
D		Double word
S		Short real
L		Long real
T		10-byte real

The default type used if no type size is specified is the last type used by a
Dump, Enter, Watch Memory, or Tracepoint Memory command.  If none of these
commands has been used during the session, the default type is byte.

<*> Examples

The two dialog commands below display watch statements (tracepoints) in the
watch window.

TP? sum

The example above instructs the CodeView debugger to suspend program executon
whenever the value of the variable sum changes.

TPS n

The example above instructs the CodeView debugger to suspend program execution
whenever the first byte at the address of n changes; the address of this byte
and its contents are displayed.  The value of n may change because of a change
in the second byte at the address of n; but that change (by itself) would have
no effect on this tracepoint.


These commands, entered while debugging a BASIC program, produce the watch
window in Figure 8.3.  Corresponding C, FORTRAN and Pascal examples are
included, with other commands, at the end of the chapter.

	Figure 8.3  Tracepoints in the Watch Window  [SEE TEXT]
----
Note
----
Setting tracepoints significantly slows execution of the program being
debugged.  The CodeView debugger has to check to see if the expression or
memory range has changed each time a source line is executed in source mode
or each time an instruction is executed in assembly mode.  However,
tracepoints do not slow execution as much as do watchpoints.
Be careful when setting tracepoints near large or nested loops.  A loop
that executes almost instantly when run from the MS-DOS operating system
can take many minutes if executed from within the debugger with several
tracepoints set.  If you enter a seemingly endless loop, press CONTROL+
BREAK or CONTROL+C to exit.  Often you can tell how far you went in the
loop by the value of the tracepoint when you exited.
====

8.4  Deleting Watch Statements

The Watch Delete command enables you to delete watch statements that were set
previously with the Watch, Watchpoint, or Tracepoint command.

When you delete a watch statement in window mode, the statement disappears and
the watch window closes around it.  For example, if there are three watch
statements in the window and you delete statement 1, the window is redrawn
with one less line.  Statement 0 remains unchanged, but statement 2 becomes
statement 1.  If there is only one statement, the window disappears.

<*> Mouse

To delete a watch statement with the mouse, point to Watch on the menu bar,
press a mouse button and drag the highlight down to the Delete Watch
selection, and then release the button.  A dialog box appears, containing all
the watch statements.  Point to the statement you want to delete and press the
ENTER key or a mouse button.  The dialog box disappears, and the watch window
is redrawn without the watch statement.

You can also delete all the statements in the watch window at once, simply by
selecting the Delete All selection.

<*> Keyboard

To execute the Delete Watch command with a keyboard command, press ALT+W to
open the Watch menu, and then type D (uppercase or lower) to select Delete
Watch.  You can also select the jDelete Watch command directly by pressing
CONTROL+U.  A dialog box appears, containing all the watch statements.  Use
the UP and DOWN arrow keys to move the cursor to the statement you want to
delete, and then press the ENTER key.  The dialog box disappears, and the
watch window is redrawn without the watch statement.

You can also delete all the statements in the watch window at once, simply by
selecting the Delete All selection.  Do this by pressing L (uppercase or
lower) after the Watch menu is open.
<*> Dialog

To delete watch statements with a dialog command, enter a command line with
the following syntax:

Y number

When you set a watch statement, it is automatically assigned a number
(starting with 0).  In window mode, the number appears to the left of the
watch statement in the watch window.  In sequential mode, you can use the
Watch List (W) command to view the numbers of current watch statements.

You can delete existing watch statements by specifying the number of the
statement you want to delete with the Delete Watch command. (The Y is a
mnemonic for "yank.")

You can use the asterisk (*) to represent all watch statements.

<*> Examples

>Y 2
>

The command above deletes watch statement 2.

>Y *
>

The command above deletes all watch statements and closes the watch window.

8.5  Listing Watchpoints and Tracepoints

The Watch List command lists all previously set watchpoints and tracepoints
with their assigned numbers and their current values.

This command is the only way to examine current watch statements in sequential
mode.  The command has little use in window mode, since watch statements are
already visible in the watch window.

<*> Mouse

The Watch List command cannot be executed with the mouse.

<*> Keyboard

The Watch List command cannot be executed with a keyboard command.

<*> Dialog

To list watch statements with a dialog command, enter a command line with the
following syntax:

W

The display is the same as the display that appears in the watch window in
window mode.

<*> Example

>W
0) code,c  :  I
1) (float)letters/words,f  :  4.777778
2) 3F65:0B20  20 20 43 4F 55 4E 54 COUNT
3) lines==11 :  0
>
----
Note
----
The command letter for the Watch List command is the same as the command
letter for the memory version of the Watch command when no memory size is
given.  The difference between the commands is that the Watch List command
never takes an argument.  The Watch command always requires at least one
argument.
====

8.6  C Examples

The seven examples shown previously in a BASIC screen would be entered in a C
debugging session as follows:

	Figure 8.4  C Watch Statements  [SEE TEXT]

The first three items in the watch window are simple watch statements.  They
display values but never cause execution to break.

The next two items are watchpoints; they cause execution to break whenever
they evaluate to true (nonzero).  The fourth item will break execution
whenever   higher  is greater than  chance, and the fifth item will break
execution whenever n is equal to 7 or 11.

The last two items are tracepoints, which cause execution to break whenever
any bytes change within a specified area of memory.  The sixth item breaks
execution whenever the value of  sum  changes; the seventh item breaks
execution whenever there is a change in the first byte at the address of n.

8.7  FORTRAN Examples

The seven examples shown previously in a BASIC screen would be entered in a
FORTRAN debugging session as follows:

	Figure 8.5  FORTRAN Watch Statements  [SEE TEXT]

The first three items in the watch window are simple watch statements.  They
display values but never cause execution to break.

The next two items are watchpoints; they cause execution to break whenever
they evaluate to true (nonzero).  The fourth item will break execution
whenever  higher  is greater than  chance, and the fifth item will break
execution whenever n is equal to 7 or 11.

The last two items are tracepoints, which cause execution to break whenever
any bytes change within a specified area of memory.  The sixth item breaks
execution whenever the value of  sum  changes; the seventh item breaks
execution whenever there is a change in the first byte at the address of n.

8.8  Pascal Examples

The seven examples shown previously in a BASIC screen would be entered in a
Pascal debugging session as follows:

	Figure 8.6  Pascal Watch Statements [SEE TEXT]

The first three items in the watch window are simple watch statements.  They
display values but never cause execution to break.

The next two items are watchpoints; they cause execution to break whenever
they evaluate to true (nonzero).  The fourth item will break execution
whenever  higher  is greater than  chance, and the fifth item will break
execution whenever n is equal to 7 or 11.

The last two items are tracepoints, which cause execution to break whenever
any bytes change within a specified area of memory.  The sixth item breaks
execution whenever the value of  sum  changes; the seventh item breaks
execution whenever there is a change in the first byte at the address of n.

8.9  Assembly Examples

By default, assembly source modules are debugged with the C expression
evaluator.  Therefore, refer to the C examples for appropriate syntax for
entering watch expressions.

In addition, however, certain C expressions tend to be more useful for
debugging assembly modules.  The following examples show some typical cases
used with watch and tracepoint commands.

<*> Examples

>WW sp L 8
>WW bp L 8
>W? wo bp+4,d
>W? by bp-2,d
>TPW arr L 5
>
The first two examples watch a range of memory.  The watch command WW sp L 8
is particularly useful because it will cause the debugger to watch the stack
dynamically; the debugger will continually display the first eight words on
the top of the stack as items are pushed and popped.  The expression WW bp L 8
is similar; it causes the debugger to watch the first eight words in memory
pointed to by BP (the framepointer).

The third example, W? wo bp+4,d  is useful if you are using the stack to pass
parameters.  In this case, the position on the stack four bytes above BP holds
one of three integer parameters.  The WO operator returns the same value as
the assembler expression WORD PTR  [bp+4]; the result is displayed in decimal.
You must use the expression bp+4 in order to watch this parameter; you cannot
specify a parameter by name.  The assembler does not emit symbolic information
for parameters.  The fourth command, W? by bp-2,d  is similar to the third,
but instead of watching a parameter, this command watches a local variable.
The operator BY returns the same value as the assembler expression BYTE PTR
[bp-2].

The final example sets a tracepoint on a range of memory, which corresponds to
the first five words of the array  arr.  Range arguments for tracepoint and
watch expressions are particularly useful for large data structures, such as
arrays.  The five examples above produce the following screen, when entered in
a CodeView debugging session:

	Figure 8.7  Assembly Watch Statements  [SEE TEXT]

.end of chapter.